package org.fhm.zdte.protocol.zrudp.service;

import org.fhm.substrate.annotation.Component;
import org.fhm.substrate.annotation.Setup;
import org.fhm.zdte.common.constant.protocol.ContentType;
import org.fhm.zdte.common.constant.protocol.PacketType;
import org.fhm.zdte.common.constant.protocol.ResponseMessageType;
import org.fhm.zdte.common.constant.subcmd.RequestCmd;
import org.fhm.zdte.common.pojo.Address;
import org.fhm.zdte.common.protocol.AbstractMessageParser;
import org.fhm.zdte.common.protocol.AbstractMessageStandard;
import org.fhm.zdte.common.protocol.AbstractMessageWrappers;
import org.fhm.zdte.common.standard.ISubCmd;
import org.fhm.zdte.common.util.CommonUtil;
import org.fhm.zdte.protocol.zrudp.pojo.ZRUDPMessageStandard;

import java.util.Objects;

/**
 * The ZRUDP that is packaged suitable Packet-Message.
 *
 * @author 谭波
 * @since 2023/11/3
 */
@Component("zrudp")
public class ZRUDPMessageWrappers extends AbstractMessageWrappers {

    @Setup
    private CommonUtil commonUtil;

    @Setup
    private AbstractMessageParser abstractMessageParser;

    @Override
    public AbstractMessageStandard getMessageByPacketType(
            PacketType type, ISubCmd subCmd, String identification,
            String target, String messageNumber,
            Integer messageLength, Address fromAddress, Address toAddress,
            String secretKey
    ) {
        ZRUDPMessageStandard message = new ZRUDPMessageStandard();
        message.setPacketType(type);
        message.setPacketSubType(subCmd);
        message.setFrom(identification);
        message.setTo(target);
        message.setMessageNumber(messageNumber);
        if (Objects.nonNull(messageLength))
            message.setMessageLength(messageLength);
        message.setFromAddress(fromAddress);
        message.setToAddress(toAddress);
        message.setSecretKey(secretKey);
        return message;
    }

    @Override
    public AbstractMessageStandard getAckMessageByPacketType(
            PacketType type, ISubCmd subCmd, String identification, String to,
            Address fromAddress, Address toAddress,
            String messageNumber
    ) {
        ZRUDPMessageStandard ackMessage = new ZRUDPMessageStandard();
        ackMessage.setPacketType(type);
        ackMessage.setPacketSubType(subCmd);
        ackMessage.setFrom(identification);
        ackMessage.setTo(to);
        ackMessage.setResponseMessageType(ResponseMessageType.MESSAGE_ACK);
        ackMessage.setFromAddress(fromAddress);
        ackMessage.setToAddress(toAddress);
        ackMessage.setMessageNumber(messageNumber);
        return ackMessage;
    }

    @Override
    public AbstractMessageStandard getFailAckMessageByPacketType(
            PacketType type, ResponseMessageType responseMessageType,
            ISubCmd subType, String from, String to, Address toAddress,
            String messageNumber
    ) {
        ZRUDPMessageStandard failAckMessage = new ZRUDPMessageStandard();
        failAckMessage.setPacketType(type);
        failAckMessage.setResponseMessageType(responseMessageType);
        failAckMessage.setPacketSubType(subType);
        failAckMessage.setFrom(from);
        failAckMessage.setTo(to);
        failAckMessage.setToAddress(toAddress);
        failAckMessage.setMessageNumber(messageNumber);
        return failAckMessage;
    }

    @Override
    public AbstractMessageStandard getSuccessfulAckMessage(PacketType type, ISubCmd subType, String from, String messageNumber) {
        ZRUDPMessageStandard successfulAckMessage = new ZRUDPMessageStandard();
        successfulAckMessage.setPacketType(type);
        successfulAckMessage.setResponseMessageType(ResponseMessageType.MESSAGE_SUCCESS);
        successfulAckMessage.setPacketSubType(subType);
        successfulAckMessage.setFrom(from);
        successfulAckMessage.setMessageNumber(messageNumber);
        return successfulAckMessage;
    }

    @Override
    public AbstractMessageStandard getMessageWithContent(
            PacketType type, ISubCmd subCmd, String from, String messageNumber, int messageLength, int messageSerial, byte[] content
    ) {
        ZRUDPMessageStandard subMessage = new ZRUDPMessageStandard();
        subMessage.setContent(content);
        subMessage.setPacketType(type);
        subMessage.setPacketSubType(subCmd);
        subMessage.setMessageNumber(messageNumber);
        subMessage.setFrom(from);
        subMessage.setMessageLength(messageLength);
        subMessage.setSerialNumber(messageSerial);
        return subMessage;
    }

    @Override
    public AbstractMessageStandard getAckMessageWithContent(
            PacketType type, ISubCmd subCmd, String identification, int messageLength,
            int messageSerial, String messageNumber, byte[] content
    ) {
        ZRUDPMessageStandard subAckMessage = new ZRUDPMessageStandard();
        subAckMessage.setResponseMessageType(ResponseMessageType.MESSAGE_ACK);
        subAckMessage.setPacketType(type);
        subAckMessage.setPacketSubType(subCmd);
        subAckMessage.setMessageNumber(messageNumber);
        subAckMessage.setMessageLength(messageLength);
        subAckMessage.setSerialNumber(messageSerial);
        subAckMessage.setFrom(identification);
        subAckMessage.setContent(content);
        return subAckMessage;
    }

    @Override
    public int getLengthOfMessageWithContent(String identification) {
        return abstractMessageParser
                .encoding(getZrudpMessageStandard(identification)).length - 1;
    }

    @Override
    public int getLengthOfAckMessageWithContent(String identification) {
        return abstractMessageParser
                .encoding(getZrudpMessageStandard(identification))
                .length - 1;
    }

    private ZRUDPMessageStandard getZrudpMessageStandard(String identify) {
        ZRUDPMessageStandard message = new ZRUDPMessageStandard();
        message.setContent(new byte[1]);
        message.setMessageNumber(commonUtil.getMessageNumber());
        message.setMessageLength(0);
        message.setSerialNumber(0);
        message.setFrom(identify);
        message.setPacketType(PacketType.ONLINE);
        message.setPacketSubType(RequestCmd.INITIAL);
        message.setContentType(ContentType.TEXT);
        message.setResponseMessageType(ResponseMessageType.MESSAGE_ACK);
        return message;
    }
}
